Skip to content

IntimateMerger Analytics Adapter : initial release#21

Open
eknis wants to merge 17 commits intomasterfrom
im-analytics-adapter
Open

IntimateMerger Analytics Adapter : initial release#21
eknis wants to merge 17 commits intomasterfrom
im-analytics-adapter

Conversation

@eknis
Copy link
Copy Markdown
Member

@eknis eknis commented Dec 3, 2025

Type of change

  • Bugfix

  • Feature

  • New bidder adapter

  • Updated bidder adapter

  • Code style update (formatting, local variables)

  • Refactoring (no functional changes, no api changes)

  • Build related changes

  • CI related changes

  • Does this change affect user-facing APIs or examples documented on http://prebid.org?

  • Other

Description of change

Other information

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 3, 2025

Tread carefully! This PR adds 1 linter error (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+1 error)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 3, 2025

Tread carefully! This PR adds 1 linter error (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+1 error)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 3, 2025

Tread carefully! This PR adds 1 linter error (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+1 error)

@eknis eknis requested review from april418 and fecker December 4, 2025 07:11
@eknis eknis marked this pull request as ready for review December 4, 2025 07:11
Copy link
Copy Markdown
Member

@fecker fecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちともろもろ確認したいのと、意識合わせしたいです。

各社のAnalytics Adaptor は、bid の分析をもろもろしているのですが、
IMでは不要なので、そのあたりは調整が必要かなと。

今の実装ならキャッシュは不要な気がしつつ、バッファリング送信機能をつけるなら必要になるかなと思っています。

  • AUCTION_INIT
    • cache の初期化(auctionId の管理用)
    • Consent データの初期化 (auctionId に紐づけて管理)
    • pvデータのみを送信(ちょっと悩み中。データとして使わないなら、ぶっちゃけまとめて送ってもいいかも? 調整中)
  • AUCTION_END
    • setTimeout で遅延実行(800 ms くらい?)
      • cache[auctionId] に入ってるものを送る
      • cache[auctionId] で、データ送信フラグ を管理
    • setTimeout で遅延実行(3分後くらい?)
      • cache[auctionId] を削除する
        − SPA でたまらないようにする
  • BID_WON
    • cache[auctionId] に 情報を蓄積する
    • データ送信済だったら(フラグがたってたら)全データを再送する

実装イメージ

case EVENTS.AUCTION_END:
  setTimeout(() => {
    analyticsAdapter.sendEvents(args.auctionId);
  }, BID_WON_WAIT); // 800ms ?
  break;

こんなことを書いてる Adaptor がいるので、バッファリングいけるんじゃないかと思ってます。

case EVENTS.BID_WON:
  const auction = cache.auctions[args.auctionId];
  if (!auction) return;

  // transactionId 単位で、cache するか
  // 配列に push した方が楽かもしれない

  // 再送を考えて、Timestamp も入れてもいいかも

  if (auction.sendStatus & REQUEST_SENT) { // すでに送信済だったら
     analyticsAdapter.sendEvents(args.auctionId); // 再送する
  }

みたいな感じでいけたりしないかなぁと思ってきました。

許諾のデータは、
libraries/intentIqUtils/getCmpData.js を参考にして
gdpr と usp (ccpa) だけとっておくと幸せになれるかなとおもってきました。

import { allConsent } from '../../src/consentHandler.js';

/**
 * Retrieves consent data from the Consent Management Platform (CMP).
 * @return {Object} An object containing the following fields:
 * - `gdprString` (string): GDPR consent string if available.
 * - `uspString` (string): USP consent string if available.
 * - `gppString` (string): GPP consent string if available.
 */
export function getCmpData() {
  const consentData = allConsent.getConsentData();

  return {
    gdprApplies: consentData?.gdpr?.gdprApplies || false,
    gdprString: typeof consentData?.gdpr?.consentString === 'string' ? consentData.gdpr.consentString : null,
    uspString: typeof consentData?.usp === 'string' ? consentData.usp : null,
    gppString: typeof consentData?.gpp?.gppString === 'string' ? consentData.gpp.gppString : null,
  };
}

@eknis
Copy link
Copy Markdown
Member Author

eknis commented Dec 9, 2025

時刻 0ms:   AUCTION_INIT
            ↓ sendStatus = 0
時刻 100ms: BID_WON #1
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 200ms: BID_WON #2
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 300ms: AUCTION_END
            ↓ 800msタイマー開始
時刻 1100ms: sendWonBidsData() 実行
             ↓ BID_WON #1, #2 をまとめて送信
             ↓ sendStatus |= WON_SENT → sendStatus = 1
時刻 1500ms: BID_WON #3(遅延)
             ↓ sendStatus & WON_SENT = 1 → 即座に個別送信
時刻 2000ms: BID_WON #4(遅延)
             ↓ sendStatus & WON_SENT = 1 → 即座に個別送信

@github-actions
Copy link
Copy Markdown

Tread carefully! This PR adds 2 linter errors (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+2 errors)

@github-actions
Copy link
Copy Markdown

Tread carefully! This PR adds 2 linter errors (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+2 errors)

@github-actions
Copy link
Copy Markdown

Tread carefully! This PR adds 2 linter errors (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+2 errors)

@eknis eknis requested a review from fecker December 25, 2025 05:51
Copy link
Copy Markdown
Member

@fecker fecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

空いちゃってしません。直してリリースしましょう。

Comment on lines +92 to +93
gdprApplies: gdprConsent.gdprApplies,
gdpr: gdprConsent.consentString,
Copy link
Copy Markdown
Member

@fecker fecker Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gdpr の consent はいらないかなと思ってきました・・・・(対応するつもりがほぼない)
他の adapter でやってたのですが gdpr に true / false (gdprApplies) を渡して、あげるのが幸せになれるかと思いました。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
gdprApplies: gdprConsent.gdprApplies,
gdpr: gdprConsent.consentString,
gdpr: gdprConsent.gdprApplies ? 1 : 0,

と短くしてなるべく小さくした方が良さげかなと。

return {
gdprApplies: gdprConsent.gdprApplies,
gdpr: gdprConsent.consentString,
usp: uspConsent
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coppa も念の為取得しておいて頂けるとうれしいです。
coppa = Number(coppaDataHandler.getCoppa());

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

追記します

const gdprConsent = request.gdprConsent || {};
const uspConsent = request.uspConsent;

return {
Copy link
Copy Markdown
Member

@fecker fecker Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

アメリカ・カナダがそこそこ入っていたので、
ggp: gppDataHandler.getConsentData().applicableSections; (Number が入ります)
ggpString: gppDataHandler.getConsentData().gppString;
で取得をお願いします。
(真面目にやるとここを見るのが良さげ?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

追加します

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ごめんなさ。ガセだったっぽい・・・orz=3


case EVENTS.AUCTION_END:
logMessage('IM Analytics: AUCTION_END', args);
this.scheduleWonBidsSend(args.auctionId);
Copy link
Copy Markdown
Member

@fecker fecker Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

細かいのですが、handleActionEnd() の方が良いのかなと思ったり。
で、その中で 2つの処理を schedule するのが良いのでは?って思いました。

別のAdapterでやってたのですが、
(あまりユースケースはないかもですが、)Cache の肥大化対策をしてるものがいました。

一定時間後(5秒 〜 10秒後)に、cache[auctions] をクリアする処理があってもいいかもす。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleActionEndへ名称変更します

* @param {Object} auctionArgs - Auction arguments
* @param {Object} consentData - Consent data object
*/
handleAucInitData(auctionArgs, consentData) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consentData って、auction の中でキャッシュされてるので、それを使いまわした方が良いのではと思ったのですが、どうすか?

handleAuction で、引数があわないのが気持ちわるい感じがします。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cacheから取得、引数が不要になるので修正します

return;
}

const consentData = auction.consentData || getConsentData(null);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cache からとるだけで大丈夫なんじゃないかなって思いました。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

たしかにおかしなことにならないのでauction.consentDataからの取得でまとめました

*/
sendWonBidsData(auctionId) {
const auction = cache.auctions[auctionId];
if (!auction || !auction.wonBids || auction.wonBids.length === 0 || (auction.sendStatus & WON_SENT)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

全部一緒に送ることを考えると最後の条件はいらないかなと。
(送れてきても、全部一緒に送ることで集計が楽になるはず)の

Copy link
Copy Markdown
Member Author

@eknis eknis Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

時刻 0ms:   AUCTION_INIT
            ↓ sendStatus = 0
時刻 100ms: BID_WON #1
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 200ms: BID_WON #2
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 300ms: AUCTION_END
            ↓ 800msタイマー開始
時刻 1100ms: sendWonBidsData() 実行
             ↓ BID_WON #1, #2 をまとめて送信
             ↓ sendStatus |= WON_SENT → sendStatus = 1
時刻 1500ms: BID_WON #3(遅延)
             ↓ sendStatus & WON_SENT = 1 → 即座に個別送信
時刻 2000ms: BID_WON #4(遅延)
             ↓ sendStatus & WON_SENT = 1 → 即座に個別送信

これが今なんですが

時刻 0ms:   AUCTION_INIT
            ↓ sendStatus = 0
時刻 100ms: BID_WON #1
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 200ms: BID_WON #2
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 300ms: AUCTION_END
            ↓ 800msタイマー開始
時刻 1100ms: sendWonBidsData() 実行
             ↓ BID_WON #1, #2 をまとめて送信
時刻 1200ms: BID_WON #3
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 1300ms: BID_WON #4
            ↓ sendStatus & WON_SENT = 0 → キャッシュに追加
時刻 1400ms: AUCTION_END
            ↓ 800msタイマー開始
時刻 1500ms: sendWonBidsData() 実行
             ↓ BID_WON #3, #4 をまとめて送信

この場合sendStatus,WON_SENT不要
みたいなかんじのほうが楽だよねってことであってますか

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

というか単純にここでチェックしなくても問題なくねという話ですかね

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

後者だと思って修正します

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あれ・・・仕様は前者の認識です!(僕が間違ってたかも?)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

次のPRに書いたのですが、ここを直すと、 sendIndividualWonBid がいらなくなる認識でした

Copy link
Copy Markdown
Member

@fecker fecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

遅くなってすいません。リリースに向かいましょう。

Comment on lines +82 to +86
function getConsentData(bidderRequests) {
if (!bidderRequests || !bidderRequests[0]) {
return EMPTY_CONSENT_DATA;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bidderRequests から取るより、Adapter から取得した方が分かりやすいかなと思ったのですが、どっちがいいっすかね・・?(0番目から取るよりという意味で。他のAnalytics Adapter はどうですか?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bidderRequestsから取得しているところを見ていたんですが
最近はちゃんと主流になっていたので全体を見直してAdapter利用するように修正しました!

Comment on lines +285 to +286
timestamp,
wonBids: auction.wonBids
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

少しでも小さくと・・・ ts, bids あたりで良いかもです。

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

変更します!


const DEFAULT_BID_WON_TIMEOUT = 800; // 0.8 second for initial batch
const DEFAULT_CID = 5126;
const API_BASE_URL = 'https://b6.im-apps.net/bids';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(完全に趣味ですが)Prebid にあわせて、bid にしませんか?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bidにします!

@github-actions
Copy link
Copy Markdown

Tread carefully! This PR adds 1 linter warning (possibly disabled through directives):

  • modules/imAnalyticsAdapter.js (+1 warning)

@eknis eknis requested a review from fecker March 26, 2026 07:55
Comment on lines +92 to +93
gdprApplies: gdprConsent.gdprApplies,
gdpr: gdprConsent.consentString,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
gdprApplies: gdprConsent.gdprApplies,
gdpr: gdprConsent.consentString,
gdpr: gdprConsent.gdprApplies ? 1 : 0,

と短くしてなるべく小さくした方が良さげかなと。

const gdprConsent = request.gdprConsent || {};
const uspConsent = request.uspConsent;

return {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ごめんなさ。ガセだったっぽい・・・orz=3


// If initial batch has been sent, send immediately
if (auction.sendStatus & WON_SENT) {
this.sendIndividualWonBid(auctionId, bidWonArgs, auction.consentData);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sendWonBidsData で送る(sendIndividualWonBid がいらなくなる)想定だったのですが、
だめでしたでしょうか?

pv, won の各送信処理は一箇所にまとめた方が良いかなと思いまして。

Copy link
Copy Markdown
Member

@fecker fecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

すません。細かいですが・・・ bidReqeust (いっぱい)なので、結構削減

transformAucInitData(auctionArgs) {
return {
ts: auctionArgs.timestamp,
adUnitCount: (auctionArgs.adUnits || []).length
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
adUnitCount: (auctionArgs.adUnits || []).length
adUnits: (auctionArgs.adUnits || []).length

なるべく小さく観点で減らしておきたいっす。

Comment on lines +174 to +175
pageUrl: window.location.href,
url: document.referrer || '',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pageUrl: window.location.href,
url: document.referrer || '',
url: window.location.href,
ref: document.referrer || '',

すんません。こっちのイメージでした w

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あ、よかったですw

Copy link
Copy Markdown
Member

@fecker fecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

悩み相談。

import { EVENTS } from '../src/constants.js';
import { sendBeacon } from '../src/ajax.js';

const DEFAULT_BID_WON_TIMEOUT = 800; // 0.8 second for initial batch
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

悩み相談なのですが、ほんとにみんなこんなに早く返してるかな・・・
感覚値ですが 1500 でもいいかもと思ってきました・・・他はどうなんでしょうか・・・

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

アダプター タイムアウト値
33acrossAnalyticsAdapter 500ms
livewrappedAnalyticsAdapter 500ms
r2b2AnalyticsAdapter 500ms
imAnalyticsAdapter 800ms
ooloAnalyticsAdapter 1500ms
yandexAnalyticsAdapter 1500ms
pubmaticAnalyticsAdapter 2000ms
atsAnalyticsAdapter 2000ms
concertAnalyticsAdapter 3000ms
adxpremiumAnalyticsAdapter 3500ms
adkernelAdnAnalyticsAdapter 4000ms

こんな感じでした。
1500くらいでもいいかもしれません

@eknis
Copy link
Copy Markdown
Member Author

eknis commented Mar 30, 2026

ごめんなさ。ガセだったっぽい・・・orz=3

ここだけちょっとわからなかったですmm

@eknis eknis requested a review from fecker March 30, 2026 12:26
@fecker
Copy link
Copy Markdown
Member

fecker commented Mar 31, 2026

ごめんなさ。ガセだったっぽい・・・orz=3

ここだけちょっとわからなかったですmm

Number 入ります!と宣言してましたが、
いまいち実装がよく分からんかった件す。(配列がきたりなど、もろもろみんな実装が違いすぎて・・・)

toString() しておけば安心かな〜と思います w

Copy link
Copy Markdown
Member

@fecker fecker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

細かいとこですが、ちょっとconsent も短くしたくなったです!

bidWonTimeout は、いったん、1500でいきましょうか。
(意外と、みんな長めに取ってるので、2000 でもいい気もしてきてますが・・・優柔不断)

その他は良さげです。

Comment on lines +163 to +177
this.handleAucInitData(args);
},

/**
* Handle auction init data - send immediately for PV tracking
* @param {Object} auctionArgs - Auction arguments
*/
handleAucInitData(auctionArgs) {
const consentData = cache.auctions[auctionArgs.auctionId].consentData;
const payload = {
url: window.location.href,
ref: document.referrer || '',
...this.transformAucInitData(auctionArgs),
consentData
};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.handleAucInitData(args);
},
/**
* Handle auction init data - send immediately for PV tracking
* @param {Object} auctionArgs - Auction arguments
*/
handleAucInitData(auctionArgs) {
const consentData = cache.auctions[auctionArgs.auctionId].consentData;
const payload = {
url: window.location.href,
ref: document.referrer || '',
...this.transformAucInitData(auctionArgs),
consentData
};
this.handleAucInitData(args, consentData);
},
/**
* Handle auction init data - send immediately for PV tracking
* @param {Object} auctionArgs - Auction arguments
*/
handleAucInitData(args, consent) {
const payload = {
url: window.location.href,
ref: document.referrer || '',
...this.transformAucInitData(args),
consent
};

こっちは、cache からとるより、引数から渡した方が見通しが良いかなと思いました。

あと細かいですが、consentData も短くしちゃいましょうか!(bid request がどんくらいくるか怖くて・・・)

Comment on lines +253 to +265
const consentData = auction.consentData;
const ts = auction.auctionInitTimestamp || Date.now();

auction.wonSent = true;
auction.wonBidsTimer = null;
const bids = auction.wonBids;
auction.wonBids = [];

sendToApi(buildApiUrlWithOptions(this.options, 'won', auctionId), {
consentData,
ts,
bids
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const consentData = auction.consentData;
const ts = auction.auctionInitTimestamp || Date.now();
auction.wonSent = true;
auction.wonBidsTimer = null;
const bids = auction.wonBids;
auction.wonBids = [];
sendToApi(buildApiUrlWithOptions(this.options, 'won', auctionId), {
consentData,
ts,
bids
});
const consent = auction.consentData;
const ts = auction.auctionInitTimestamp || Date.now();
auction.wonSent = true;
auction.wonBidsTimer = null;
const bids = auction.wonBids;
auction.wonBids = [];
sendToApi(buildApiUrlWithOptions(this.options, 'won', auctionId), {
bids,
ts,
consent,
});

こちらも、consent と 短くしちゃいたいっす!

@eknis
Copy link
Copy Markdown
Member Author

eknis commented Mar 31, 2026

指摘いただいた点修正しました!
bidWonTimeoutは一つ前に修正してます

@eknis eknis requested a review from fecker March 31, 2026 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants